#pragma once

#include <sstream>
#include "ObjectProperty.h"
#include "Action.h"

namespace My {

template <typename T>
bool BasicProperty<T>::Visible(const EditableList & list) const
{
	EditableList tmp(list);
	bool result = true;
	for (EditableList::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
		result &= Visible(* * it);
	return result;
}

template <typename T>
bool BasicProperty<T>::ReadOnly(const EditableList & list) const
{
	EditableList tmp(list);
	bool result = false;
	for (EditableList::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
		result |= ReadOnly(* * it);
	return result;
}

template <typename T>
bool BasicProperty<T>::GetValue(const EditableList & list, T & value)
{
	if (list.empty())
		return false;
	EditableList tmp(list);
	EditableList::const_iterator it = tmp.begin();
	if (!GetValue(* * it, value))
		return false;
	T v;
	for (++it; it != tmp.end(); ++it)
		if (!GetValue(* * it, v) || v != value)
			return false;
	return true;
}

template <typename T>
void BasicProperty<T>::SetValue(const EditableList & list, const T & value)
{
	MultiAction action;
	EditableList tmp(list);
	EditableList::iterator it;
	for (it = tmp.begin(); it != tmp.end(); ++it)
		SetValue(* * it, value);
}

// Property

template <typename T>
Widget * Property<T>::CreateControl(const EditableList & list)
{
	return new TypedControl<T>(* this, list);
}

template <typename T>
void Property<T>::FreeControl(Widget * pControl)
{
	delete pControl;
}

// PersistentPropertyBase

template <typename T>
void PersistentPropertyBase<T>::Deserialize(xml::const_node const & n, EditableObject & obj) const
{
	Base::Deserialize(n, obj);
	T value;
	if (n.query_attr("value", value))
		SetValue(obj, value);
}

template <typename T>
void PersistentPropertyBase<T>::Serialize(xml::node const & n, const EditableObject & obj) const
{
	Base::Serialize(n, obj);
	T value;
	if (!GetValue(obj, value))
		return;
	n["value"] = value;
}

// PropertyImpl

template <typename T>
PropertyImpl<T>::PropertyImpl()
{
}

template <typename T>
bool PropertyImpl<T>::Accept(const EditableObject & obj) const
{
	return	(!m_pGet || m_pGet->Accept(obj)) &&
			(!m_pSet || m_pSet->Accept(obj)) &&
			(!m_pReadOnly || m_pReadOnly->Accept(obj)) &&
			(!m_pVisible || m_pVisible->Accept(obj));
}

template <typename T>
bool PropertyImpl<T>::ReadOnly(const EditableObject & obj) const
{
	bool value;
	return 	(m_pReadOnly && m_pReadOnly->GetValue(obj, value) ? value : false) || !m_pSet;
}

template <typename T>
bool PropertyImpl<T>::Visible(const EditableObject & obj) const
{
	bool value;
	return m_pVisible && m_pVisible->GetValue(obj, value) ?
		value : true;
}

template <typename T>
bool PropertyImpl<T>::GetValue(const EditableObject & obj, T & value) const
{
	return m_pGet ? 
		m_pGet->GetValue(obj, value) : false;
}

template <typename T>
void PropertyImpl<T>::SetValue(EditableObject & obj, const T & value) const
{
	if (m_pSet)
		m_pSet->SetValue(obj, value);
}

template <typename T>
String PropertyImpl<T>::GetHint(const EditableList &) const
{
	return m_Hint;
}

template <typename T>
template <typename RW>
PropertyImpl<T> & PropertyImpl<T>::ReadWrite(RW rw)
{
	ReadWriteSPtr pRW = My::ReadWrite<T>(rw);
	m_pGet = pRW;
	m_pSet = pRW->ReadOnly() ? WriteSPtr() : pRW;
	return * this;
}

template <typename T>
template <typename S>
PropertyImpl<T> & PropertyImpl<T>::ReadWrite(BasicProperty<S> & owner, T (S::* ptr))
{
	ReadWriteSPtr pRW = My::ReadWrite(owner, ptr);
	m_pGet = pRW;
	m_pSet = pRW->ReadOnly() ? WriteSPtr() : pRW;
	return * this;
}

template <typename T>
template <typename R>
PropertyImpl<T> & PropertyImpl<T>::Read(R r)
{
	m_pGet = My::Read<T>(r);
	return * this;
}

template <typename T>
template <typename S>
PropertyImpl<T> & PropertyImpl<T>::Read(BasicProperty<S> & owner, T (S::* ptr))
{
	m_pGet = My::ReadWrite(owner, ptr);
	return * this;
}

template <typename T>
template <typename W>
PropertyImpl<T> & PropertyImpl<T>::Write(W w)
{
	m_pSet = My::Write<T>(w);
	return * this;
}

template <typename T>
template <typename R>
PropertyImpl<T> & PropertyImpl<T>::ReadOnly(R r)
{
	m_pReadOnly = My::Read<bool>(r);
	return * this;
}

template <typename T>
template <typename R>
PropertyImpl<T> & PropertyImpl<T>::Visible(R r)
{
	m_pVisible = My::Read<bool>(r);
	return * this;
}

template <typename T>
PropertyImpl<T> & PropertyImpl<T>::Hint(const ResourceString & hint)
{
	m_Hint = hint;
	return * this;
}

/*
template <typename T>
PropertyImpl<T> & PropertyImpl<T>::Init(const String & hint,
	ReadWriteAccess<T> * pValue,
	ReadAccess<bool> * pReadOnly,
	ReadAccess<bool> * pVisible)
{
	m_Hint = hint;
	m_pValue.reset(pValue);
	m_pReadOnly.reset(pReadOnly);
	m_pVisible.reset(pVisible);
	return * this;
}

template <typename T>
template <typename C>
PropertyImpl<T> & PropertyImpl<T>::Init(const String & hint, 
	T (C::* pGet)() const, void (C::* pSet)(T),
	ReadAccess<bool> * pReadOnly, ReadAccess<bool> * pVisible)
{
	return Init(hint, ReadWrite<T>(pGet, pSet), pReadOnly, pVisible);
}

template <typename T>
template <typename C>
PropertyImpl<T> & PropertyImpl<T>::Init(const String & hint, 
	const T & (C::* pGet)() const, void (C::*pSet)(const T &),
	ReadAccess<bool> * pReadOnly, ReadAccess<bool> * pVisible)
{
	return Init(hint, ReadWrite<T>(pGet, pSet), pReadOnly, pVisible);
}

template <typename T>
template <typename S>
PropertyImpl<T> & PropertyImpl<T>::Init(const String & hint, 
	BasicProperty<S> & owner, T (S::* pMember),
	ReadAccess<bool> * pReadOnly, ReadAccess<bool> * pVisible)
{
	return Init(hint, ReadWrite<T>(owner, pMember), pReadOnly, pVisible);
}

template <typename T>
PropertyImpl<T> & PropertyImpl<T>::ReadOnly(ReadAccess<bool> * ptr)
{
	m_pReadOnly.reset(ptr);
	return * this;
}

template <typename T>
template <class B>	
PropertyImpl<T> & PropertyImpl<T>::ReadOnly(B b)
{
	return ReadOnly(Get(b));
}

template <typename T>
PropertyImpl<T> & PropertyImpl<T>::Visible(ReadAccess<bool> * ptr)
{
	m_pVisible.reset(ptr);
	return * this;
}

template <typename T>
template <class B> 
PropertyImpl<T> & PropertyImpl<T>::Visible(B b)
{
	return Visible(Get(b));
}
*/

// TypedControlBase

template <typename T> 
TypedControlBase<T>::TypedControlBase(BasicProperty<T> & p, const EditableList & list) :
	m_Property(p), m_Objects(list)
{
}

template <typename T> 
bool TypedControlBase<T>::GetText(String & s)
{
	T value;
	if (!m_Property.GetValue(m_Objects, value))
		return false;
	std::ostringstream out;
	out << value;
	s = out.str();
	return true;
}

template <typename T> 
void TypedControlBase<T>::SetText(const String & s)
{
	T value;
	std::istringstream in;
	in.str(s);
	in >> value;
	if (in.fail())
		return;
	m_Property.SetValue(m_Objects, value);
}

template <typename T> 
void TypedControlBase<T>::HandleUpdateUI()
{
	SetVisible(m_Property.Visible(m_Objects));
	SetReadOnly(m_Property.ReadOnly(m_Objects));
}

} // My
